#include"graph.h"
#include"../../../log/log_mgr.h"
#include"../config.h"
#include"../../util.h"

QueryGraph::QueryGraph(){}

QueryGraph::QueryGraph(iostream *input)
{
	string line;
	vector<string> v;
	while(!input->eof())
	{
		getline(*input, line);
		v.push_back(line);
	}
	for(int i = 0; i < v.size(); ++ i)
	{
		string &node_s = v[i];
		int del = node_s.find(":");
		string node = node_s.substr(0, del);
		add_node(node);
	}
	for(int i = 0; i < v.size(); ++ i)
	{
		string &node_s = v[i];
		int del = node_s.find(":");
		QueryNode &node1 = (*graph.find(node_s.substr(0, del))).second;
		string neig_s = node_s.substr(del + 1, node_s.length() - del - 1);
		//util::LogMgr::record(node1.name+":");
		vector<string> neig = util::tokenize_h(neig_s, " | ");
		for(int j = 0; j < neig.size(); ++ j)
		{
			//util::LogMgr::record(neig[j]+" | ");
			QueryNode &node2 = (*graph.find(neig[j])).second;
			add_edge(node1, node2);
		}
		//util::LogMgr::record("\n");
	}
}
void QueryGraph::add_node(string name)
{
	graph.insert(pair<string, QueryNode>(name, QueryNode(name)));
}

void QueryGraph::add_node(QueryNode node)
{
	graph.insert(pair<string, QueryNode>(node.name, node));
}

void QueryGraph::add_edge(QueryNode &n1, QueryNode &n2)
{
	n1.add_edge(n2);
	n2.add_edge(n1);
}

QueryNode QueryGraph::get_node(string name)
{
	return (*graph.find(name)).second;
}

void QueryGraph::update_node(NodeReformer &reformer)
{
	if(atoi(Config::get("new_node").c_str()) == 0)
	{
		map<string, QueryNode>::iterator itr;
		for(itr = graph.begin(); itr != graph.end(); ++ itr)
			reformer.reform((*itr).second);
	}
	else
	{
		//add new node that graph doesn't have
		//add edge between node and refined node
		map<string, QueryNode>::iterator itr;
		map<string, vector<string>> reform_map;
		map<string, vector<string>>::iterator ref_itr;
		for(itr = graph.begin(); itr != graph.end(); ++ itr)
		{
			QueryNode node = reformer.reform_new((*itr).second);
			add_node(node);
			ref_itr = reform_map.find(node.name);
			if(ref_itr == reform_map.end())
			{
				vector<string> v;
				v.push_back((*itr).first);
				reform_map.insert(pair<string, vector<string>>(node.name, v));
			}
			else
				(*ref_itr).second.push_back((*itr).first);
		}
		for(ref_itr = reform_map.begin(); ref_itr != reform_map.end(); ++ ref_itr)
		{
			QueryNode &refined_node = (*graph.find((*ref_itr).first)).second;
			vector<string> &elem = (*ref_itr).second;
			for(int i = 0; i < elem.size(); ++ i)
			{
				QueryNode &related_node = (*graph.find(elem[i])).second;
				add_edge(refined_node, related_node);
			}
		}
	}
}

void QueryGraph::update_edge(EdgeChecker &checker)
{
	map<string, QueryNode>::iterator graph_itr1, graph_itr2;
	for(graph_itr1 = graph.begin(); graph_itr1 != graph.end(); ++ graph_itr1)
	{
		QueryNode &node1 = (*graph_itr1).second;
		if((checker.instance == "DistanceChecker"||
			checker.instance == "RawDistanceChecker") && 
			node1.name.length() < 3)
		{
			add_edge(node1, node1);
			continue;
		}
		for(graph_itr2 = graph.begin(); graph_itr2 != graph.end(); ++ graph_itr2)
		{
			QueryNode &node2 = (*graph_itr2).second;
			if(checker.satisfied(node1, node2))
				add_edge(node1, node2);
		}
	}
}

void QueryGraph::flood(vector<vector<string>> &groups)
{
	map<string, QueryNode>::iterator itr;
	set<string> visited;
	for(itr = graph.begin(); itr != graph.end(); ++ itr)
	{
		vector<string> v;
		search((*itr).second, v, visited);
		if(v.size() > 0){
			//util::LogMgr::record("\n");
			groups.push_back(v);
		}
	}
}

//void QueryGraph::search(QueryNode &seed, vector<string> &elem, set<string> &visited)
//{
//	if(visited.find(seed.name) == visited.end())
//	{
//		util::LogMgr::record(seed.name + "\n");
//		visited.insert(seed.name);
//		elem.push_back(seed.name);
//		for(map<string, QueryNode&>::iterator itr = seed.adj_list.begin(); 
//				itr != seed.adj_list.end(); 
//				++ itr)
//		{
//			if(visited.find((*itr).second.name) == visited.end())
//				search((*itr).second, elem, visited);
//		}
//	}
//}

//void QueryGraph::search(QueryNode &seed, vector<string> &elem, set<string> &visited)
//{
//	if(visited.find(seed.name) == visited.end())
//	{
//		vector<string> query_queue;
//		query_queue.push_back(seed.name);
//		for(int i = 0; i < query_queue.size(); ++ i)
//		{
//			if(visited.find(query_queue[i]) == visited.end())
//			{
//				visited.insert(query_queue[i]);
//				elem.push_back(query_queue[i]);						
//			}
//			QueryNode &node = get_node(query_queue[i]);
//			for(map<string, QueryNode&>::iterator itr = node.adj_list.begin(); 
//					itr != node.adj_list.end(); 
//					++ itr)
//				if(visited.find((*itr).first) == visited.end())
//					query_queue.push_back((*itr).first);
//		}
//	}
//}
void QueryGraph::search(QueryNode &seed, vector<string> &elem, set<string> &visited)
{
	if(visited.find(seed.name) == visited.end())
	{
		elem.push_back(seed.name);
		visited.insert(seed.name);
		for(int i = 0; i < elem.size(); ++ i)
		{
			QueryNode &node = get_node(elem[i]);
			for(map<string, QueryNode&>::iterator itr = node.adj_list.begin(); 
					itr != node.adj_list.end(); 
					++ itr)
				if(visited.find((*itr).first) == visited.end())
				{
					visited.insert((*itr).first);
					elem.push_back((*itr).first);
				}
		}
	}
}